package com.mbt.mobile.bluetooth.manager;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.MIDletStateChangeException;

import com.sun.perseus.platform.BufferedInputStream;

/**
 * A class that demonstrates Bluetooth communication between client mode device
 * and server mode PC through serial port profile.
 */
public class BluetoothConnectionManager implements DiscoveryListener {

	/** The Constant DEBUG. */
	static final boolean DEBUG = false;

	/** The Constant DEBUG_address. */
	static final String DEBUG_ADDRESS = "B482FEC0EE2E"; // N6630
	// static final String DEBUG_address = "0x0123456789AF";
	/** The uuid. */
	protected final UUID uuid = new UUID(0x1101); // serial port profile
	String msg = null;

	/** The inquiry mode. */
	protected int inquiryMode = DiscoveryAgent.GIAC; // no pairing is needed

	/** The connection options. */
	protected int connectionOptions = ServiceRecord.NOAUTHENTICATE_NOENCRYPT;

	/** The stream. */
	private StreamConnection stream = null;

	/** The in. */
	private InputStream in = null;

	/** The is complete. */
	private boolean isComplete = false;

	/** The is connected. */
	private boolean isConnected = false;

	/** The out. */
	private OutputStream out = null;

	/** The stop token. */
	protected int stopToken = 255;

	/** The device list. */
	protected Vector deviceList = new Vector();

	/**
	 * Checks if is complete.
	 * 
	 * @return true, if is complete
	 */
	public boolean isComplete() {
		return isComplete;
	}

	/**
	 * Checks if is connected.
	 * 
	 * @return true, if is connected
	 */
	public boolean isConnected() {
		return isConnected;
	}

	/**
	 * Instantiates a new bluetooth connection manager.
	 */
	public BluetoothConnectionManager() {
		try {
			startApp();
		} catch (MIDletStateChangeException ex) {
		}
	}

	/**
	 * Start app.
	 * 
	 * @throws MIDletStateChangeException
	 *             the mI dlet state change exception
	 */
	public void startApp() throws MIDletStateChangeException {

		if (DEBUG) // skip inquiry in debug mode
		{
			startServiceSearch(new RemoteDevice(DEBUG_ADDRESS) {
			});
		} else {
			try {
				startDeviceInquiry();
			} catch (Throwable t) {
			}
		}
	}

	/**
	 * Start device inquiry.
	 */
	private void startDeviceInquiry() {
		try {
			DiscoveryAgent agent = getAgent();
			agent.startInquiry(inquiryMode, this);

		} catch (Exception e) {
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seejavax.bluetooth.DiscoveryListener#deviceDiscovered(javax.bluetooth.
	 * RemoteDevice, javax.bluetooth.DeviceClass)
	 */
	public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
		deviceList.addElement(btDevice);
	}

	// called when service search gets complete
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.bluetooth.DiscoveryListener#inquiryCompleted(int)
	 */
	public void inquiryCompleted(int discType) {
		isComplete = true;
	}

	/**
	 * Start service search.
	 * 
	 * @param device
	 *            the device
	 */
	public void startServiceSearch(RemoteDevice device) {
		try {
			UUID uuids[] = new UUID[] { uuid };
			getAgent().searchServices(null, uuids, device, this);
		} catch (Exception e) {
		}
	}

	/**
	 * This method is called when a service(s) are discovered.This method starts
	 * a thread that handles the data exchange with the server.
	 * 
	 * @param transId
	 *            the trans id
	 * @param records
	 *            the records
	 */
	public void servicesDiscovered(int transId, ServiceRecord[] records) {
		for (int i = 0; i < records.length; i++) {
			ServiceRecord rec = records[i];
			String url = rec.getConnectionURL(connectionOptions, false);
			handleConnection(url);
		}
		isConnected = true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.bluetooth.DiscoveryListener#serviceSearchCompleted(int, int)
	 */
	public void serviceSearchCompleted(int transID, int respCode) {
		String msg = null;
		switch (respCode) {
		case SERVICE_SEARCH_COMPLETED:
			msg = "the service search completed normally";
			break;
		case SERVICE_SEARCH_TERMINATED:
			msg = "the service search request was cancelled by a call to DiscoveryAgent.cancelServiceSearch()";
			break;
		case SERVICE_SEARCH_ERROR:
			msg = "an error occurred while processing the request";
			break;
		case SERVICE_SEARCH_NO_RECORDS:
			msg = "no records were found during the service search";
			break;
		case SERVICE_SEARCH_DEVICE_NOT_REACHABLE:
			msg = "the device specified in the search request could not be reached or the local device could not establish a connection to the remote device";
			break;
		}
	}

	/*-
	 *   -------  The actual connection handling. -------
	 */
	/**
	 * Handle connection.
	 * 
	 * @param url
	 *            the url
	 */
	private void handleConnection(final String url) {
		try {
			stream = (StreamConnection) Connector.open(url);

		} catch (IOException e) {
		}
	}

	/*-
	 *   -------  Utils section - contains utility functions -------
	 */
	/**
	 * Gets the agent.
	 * 
	 * @return the agent
	 */
	private DiscoveryAgent getAgent() {
		try {
			return LocalDevice.getLocalDevice().getDiscoveryAgent();
		} catch (BluetoothStateException e) {
		}
		return null;
	}

	/**
	 * Gets the device str.
	 * 
	 * @param btDevice
	 *            the bt device
	 * @return the device str
	 */
	public String getDeviceStr(RemoteDevice btDevice) {
		return getFriendlyName(btDevice) + " - 0x"
				+ btDevice.getBluetoothAddress();
	}

	/**
	 * Gets the friendly name.
	 * 
	 * @param btDevice
	 *            the bt device
	 * @return the friendly name
	 */
	private String getFriendlyName(RemoteDevice btDevice) {
		try {
			return btDevice.getFriendlyName(false);
		} catch (IOException e) {
			return "Unknown";
		}
	}

	/**
	 * Gets the output stream.
	 * 
	 * @return the output stream
	 */
	public OutputStream getOutputStream() {
		return out;
	}

	/**
	 * Gets the input stream.
	 * 
	 * @return the input stream
	 */
	public BufferedInputStream getInputStream() {
		return new BufferedInputStream(in);
	}

	public Image getImage() throws Exception {
	    // then open a steam and read an image
        byte[] imgData = null;

        try {
            InputStream in = stream.openInputStream();
            if(in.available() <0)
            	return null;
            // read a length first
            int length = in.read() << 8;
            length |= in.read();

            if (length <= 0) {
                throw new IOException("Can't read a length");
            }

            // read the image now
            imgData = new byte[length];
            length = 0;

            while (length != imgData.length) {
                int n = in.read(imgData, length, imgData.length - length);

                if (n == -1) {
                    throw new IOException("Can't read a image data");
                }

                length += n;
            }

            in.close();
        } catch (IOException e) {
            System.err.println("Can't read from server for: " );

        } finally {
            // close stream connection anyway
        }

        // ok, may it's a chance
        Image img = null;

        try {
            img = Image.createImage(imgData, 0, imgData.length);
        } catch (Exception e) {
        }

        return img;

	}
	public String  recieveMessages()
    {
        byte[] data = null;   
        try 
        {  if(in == null)
        	in = stream.openDataInputStream();
        if(in.available()>0){
           int length = in.read();       
           if(length <= 0){
        	   return null;
           }
           data= new byte[length];
           length = 0;
       
           while (length != data.length) 
           {     
                   int ch = in.read(data, length, data.length - length);

                   if (ch == -1)
                   {
                     throw new IOException("Can't read data");
                   }
                   length += ch;
           }      

        }
        }
        catch (IOException e) 
        {
              System.err.println(e);
        } 
        
        return data != null? new String(data) : null;
    }
    

	/**
	 * Gets the device l ist.
	 * 
	 * @return the device l ist
	 */
	public Vector getDeviceLIst() {
		return deviceList;
	}

	/**
	 * Send messages.
	 * 
	 * @param strData
	 *            the str data
	 */
	public String sendMessages(String strData) {
		
		try {
			out = stream.openOutputStream();
			out.write(strData.length());
			out.write(strData.getBytes());
			out.flush();
			out.close();
			//msg = "Success";
		} catch (IOException ex) {
			msg = "Failed : " + ex.getMessage();
		}
		return msg;
	}
}
